<div class="content-section introduction">
    <div class="feature-intro">
        <h1>MultiSelect</h1>
        <p>MultiSelect is used to multiple values from a list of options.</p>
    </div>
    <app-demoActions github="multiselect" stackblitz="multiselect-demo"></app-demoActions>
</div>

<div class="content-section implementation">
    <div class="card">
        <h5>Template Mode</h5>
        <p-multiSelect [options]="cities" [(ngModel)]="selectedCities1" defaultLabel="Select a City" optionLabel="name" selectedItemsLabel="{0} items selected"></p-multiSelect>

        <h5>Elipsis Mode</h5>
        <p-multiSelect [options]="cities" [(ngModel)]="selectedCities2" defaultLabel="Select a City" optionLabel="name"></p-multiSelect>

        <h5>Chips</h5>
        <p-multiSelect [options]="cities" [(ngModel)]="selectedCities3" defaultLabel="Select a City" optionLabel="name" display="chip"></p-multiSelect>

        <h5>Grouped</h5>
        <p-multiSelect [options]="groupedCities" [group]="true" [(ngModel)]="selectedCities4" defaultLabel="Select a City" scrollHeight="250px" display="chip">
            <ng-template let-group pTemplate="group">
                <div class="flex align-items-center">
                    <img src="assets/showcase/images/demo/flag/flag_placeholder.png" [class]="'mr-2 flag flag-' + group.value" style="width: 20px"/>
                    <span>{{group.label}}</span>
                </div>
            </ng-template>
        </p-multiSelect>

        <h5>Advanced with Templating and Filtering</h5>
        <p-multiSelect [options]="countries" [(ngModel)]="selectedCountries1" defaultLabel="Select a Country" optionLabel="name" class="multiselect-custom">
            <ng-template let-value pTemplate="selectedItems">
                <div class="country-item country-item-value" *ngFor="let option of selectedCountries1">
                    <img src="assets/showcase/images/demo/flag/flag_placeholder.png" [class]="'flag flag-' + option.code.toLowerCase()" />
                    <div>{{option.name}}</div>
                </div>
                <div *ngIf="!selectedCountries1 || selectedCountries1.length === 0" class="country-placeholder">
                    Select Countries
                </div>
            </ng-template>
            <ng-template let-country pTemplate="item">
                <div class="country-item">
                    <img src="assets/showcase/images/demo/flag/flag_placeholder.png" [class]="'flag flag-' + country.code.toLowerCase()" />
                    <div>{{country.name}}</div>
                </div>
            </ng-template>
        </p-multiSelect>

        <h5>Virtual Scroll</h5>
        <p-multiSelect [options]="virtualCountries" [showToggleAll]="false" [(ngModel)]="selectedCountries2" optionLabel="name" [virtualScroll]="true" [filter]="true" [virtualScrollItemSize]="43" class="multiselect-custom-virtual-scroll">
            <ng-template let-country pTemplate="item">
                <div class="country-item">
                    <img src="assets/showcase/images/demo/flag/flag_placeholder.png" [class]="'flag flag-' + country.code.toLowerCase()" />
                    <div>{{country.name}}</div>
                </div>
            </ng-template>
        </p-multiSelect>
    </div>
</div>

<div class="content-section documentation">
    <p-tabView>
        <p-tabPanel header="Documentation">
            <h5>Import</h5>
<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
import &#123;MultiSelectModule&#125; from 'primeng/multiselect';
</app-code>

            <h5>Getting Started</h5>
            <p>MultiSelect requires a value to bind and a collection of options.</p>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-multiSelect [options]="cities" [(ngModel)]="selectedCities" optionLabel="name"&gt;&lt;/p-multiSelect&gt;
</app-code>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
interface City &#123;
    name: string,
    code: string
&#125;

export class MultiSelectDemo &#123;

    cities: City[];

    selectedCities: City[];

    constructor() &#123;
        this.cities = [
            &#123;name: 'New York', code: 'NY'&#125;,
            &#123;name: 'Rome', code: 'RM'&#125;,
            &#123;name: 'London', code: 'LDN'&#125;,
            &#123;name: 'Istanbul', code: 'IST'&#125;,
            &#123;name: 'Paris', code: 'PRS'&#125;
        ];
    &#125;

&#125;
</app-code>

            <h5>Value Binding</h5>
            <p>The option itself is bound to the model by default, use <i>optionValue</i> to customize the property to pass as the value.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-multiSelect [options]="cities" [(ngModel)]="selectedCityCodes" optionLabel="name" optionValue="code"&gt;&lt;/p-multiSelect&gt;
</app-code>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
interface City &#123;
    name: string,
    code: string
&#125;

export class MultiSelectDemo &#123;

    cities: City[];

    selectedCityCodes: string[];

    constructor() &#123;
        this.cities = [
            &#123;name: 'New York', code: 'NY'&#125;,
            &#123;name: 'Rome', code: 'RM'&#125;,
            &#123;name: 'London', code: 'LDN'&#125;,
            &#123;name: 'Istanbul', code: 'IST'&#125;,
            &#123;name: 'Paris', code: 'PRS'&#125;
        ];
    &#125;

&#125;
</app-code>

            <h5>Chips Display</h5>
            <p>A comma separated list is used by default to display selected items whereas alternative chip mode is provided using the <i>display</i> property to visualize the items as tokens.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-multiSelect [options]="cities" [(ngModel)]="selectedCities" display="chip"&gt;&lt;/p-multiSelect&gt;
</app-code>

            <h5>Disabled Options</h5>
            <p>Particular options can be prevented from selection using the <i>optionDisabled</i> property.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-multiSelect [options]="cities" [(ngModel)]="selectedCities" optionLabel="name" optionDisabled="inactive"&gt;&lt;/p-multiSelect&gt;
</app-code>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
export class MultiSelectDemo &#123;

    cities: City[];

    selectedCities: City[];

    constructor() &#123;
        this.cities = [
            &#123;name: 'New York', code: 'NY', inactive: false&#125;,
            &#123;name: 'Rome', code: 'RM', inactive: true&#125;,
            &#123;name: 'London', code: 'LDN', inactive: false&#125;,
            &#123;name: 'Istanbul', code: 'IST', inactive: true&#125;,
            &#123;name: 'Paris', code: 'PRS', inactive: false&#125;
        ];
    &#125;

&#125;
</app-code>

            <h5>Model Driven Forms</h5>
            <p>MultiSelect can be used in a model driven form as well.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-multiSelect [options]="cities" formControlName="selectedCities"&gt;&lt;/p-multiSelect&gt;
</app-code>

            <h5>Custom Content</h5>
            <p>For custom content support when displaying options, define a ng-template named <i>item</i> where the local ng-template variable refers to an option in the options collection. 
                Similarly <i>selectedItems</i> template can be used to customize when displaying the selected options. Additionally a custom header, filter, footer and empty filter message can be provided using <i>header</i>, <i>filter</i>, <i>footer</i> and <i>emptyfilter</i> templates. 
                In addition when grouping is enabled, <i>group</i> template is available to customize the option groups. All templates get the option instance as the default local template variable.</p>

<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-multiSelect [options]="countries" [(ngModel)]="selectedCountries" defaultLabel="Select a Country" optionLabel="name" class="multiselect-custom"&gt;
    &lt;ng-template pTemplate="header"&gt;
        Header Content
    &lt;/ng-template&gt;
    &lt;ng-template let-value pTemplate="selectedItems"&gt;
        &lt;div class="country-item country-item-value" *ngFor="let option of selectedCountries"&gt;
            &lt;img src="assets/showcase/images/demo/flag/flag_placeholder.png" [class]="'flag flag-' + option.code.toLowerCase()" /&gt;
            &lt;div&gt;&#123;&#123;option.name&#125;&#125;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div *ngIf="!selectedCountries || selectedCountries.length === 0" class="country-placeholder"&gt;
            Select Countries
        &lt;/div&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="filter" let-options="options"&gt;
        &lt;div class="p-inputgroup"&gt;
            &lt;span class="p-inputgroup-addon"&gt;&lt;i class="pi pi-search"&gt;&lt;/i&gt;&lt;/span&gt;
            &lt;input type="text" pInputText placeholder="Filter" [(ngModel)]="filterValue" (keyup)="options.filter($event)"&gt;
        &lt;/div&gt;
        &lt;button pButton icon="pi pi-times" class="ml-3" (click)="myResetFunction(options)"&gt;&lt;/button&gt;
    &lt;/ng-template&gt;
    &lt;ng-template let-country pTemplate="item"&gt;
        &lt;div class="country-item"&gt;
            &lt;img src="assets/showcase/images/demo/flag/flag_placeholder.png" [class]="'flag flag-' + country.code.toLowerCase()" /&gt;
            &lt;div&gt;&#123;&#123;country.name&#125;&#125;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/ng-template&gt;
    &lt;ng-template pTemplate="footer"&gt;
        Footer Content
    &lt;/ng-template&gt;
&lt;/p-multiSelect&gt;
</app-code>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
import &#123;MultiSelectFilterOptions&#125; from 'primeng/multiselect';
....
interface Country &#123;
    name: string,
    code: string
&#125;

export class MultiSelectDemo &#123;

    countries: Country[];

    selectedCountries: Country[];

    filterValue = '';

    constructor() &#123;
        this.countries = [
            &#123;name: 'Australia', code: 'AU'&#125;,
            &#123;name: 'Brazil', code: 'BR'&#125;,
            &#123;name: 'China', code: 'CN'&#125;,
            &#123;name: 'Egypt', code: 'EG'&#125;,
            &#123;name: 'France', code: 'FR'&#125;,
            &#123;name: 'Germany', code: 'DE'&#125;,
            &#123;name: 'India', code: 'IN'&#125;,
            &#123;name: 'Japan', code: 'JP'&#125;,
            &#123;name: 'Spain', code: 'ES'&#125;,
            &#123;name: 'United States', code: 'US'&#125;
        ];
    &#125;

    myResetFunction(options: MultiSelectFilterOptions) &#123;
        options.reset();
        this.filterValue = '';
    &#125;

&#125;
</app-code>

            <h5>Virtual Scrolling</h5>
            <p>VirtualScrolling is an efficient way of rendering the options by displaying a small subset of data in the viewport at any time. When dealing with huge number of options, it is suggested to enable VirtualScrolling
                to avoid performance issues. Usage is simple as setting <i>virtualScroll</i> property to true and defining virtualScrollItemSize to specify the height of an item.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-multiSelect [options]="cities" formControlName="selectedCities" optionLabel="name" [virtualScroll]="true" [virtualScrollItemSize]="30"&gt;&lt;/p-multiSelect&gt;
</app-code>

            <h5>Animation Configuration</h5>
            <p>Transition of the open and hide animations can be customized using the showTransitionOptions and hideTransitionOptions properties,
                example below disables the animations altogether.</p>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-multiSelect [options]="cities" formControlName="selectedCities" optionLabel="name" [showTransitionOptions]="'0ms'" [hideTransitionOptions]="'0ms'"&gt;&lt;/p-multiSelect&gt;
</app-code>

            <h5>Selected Items Label</h5>
            <p>When the max number of selected items to display is reached, an ellipsis is used to indicate a text overflow. This behavior can be customized with the <i>selectedItemsLabel</i> property that accepts a template string such as ""&#123;0&#125;" items selected" where the parameter is the number
                of selected items.</p>

            <h6>Ellipsis Overflow</h6>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-multiSelect [options]="cities" [(ngModel)]="selectedCities" optionLabel="name" &gt;&lt;/p-multiSelect&gt;
</app-code>

            <h6>Custom Label</h6>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;p-multiSelect [options]="cities" [(ngModel)]="selectedCities" optionLabel="name" [maxSelectedLabels]="5" [selectedItemsLabel]="'&#123;0&#125; items selected'"&gt;&lt;/p-multiSelect&gt;
</app-code>

            <h5>Properties</h5>
            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                    <tr>
                        <th>Name</th>
                        <th>Type</th>
                        <th>Default</th>
                        <th>Description</th>
                    </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>appendTo</td>
                            <td>any</td>
                            <td>null</td>
                            <td>Target element to attach the overlay, valid values are "body" or a local ng-template variable of another element (note: use binding with brackets for template variables, e.g. [appendTo]="mydiv" for a div element having #mydiv as variable name).</td>
                        </tr>
                        <tr>
                            <td>ariaFilterLabel</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Defines a string that labels the filter input.</td>
                        </tr>
                        <tr>
                            <td>label</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Label of the input for accessibility.</td>
                        </tr>
                        <tr>
                            <td>ariaLabelledBy</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Establishes relationships between the component and label(s) where its value should be one or more element IDs.</td>
                        </tr>
                        <tr>
                            <td>autofocusFilter</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Applies focus to the filter element when the overlay is shown.</td>
                        </tr>
                        <tr>
                            <td>autoZIndex</td>
                            <td>boolean</td>
                            <td>true</td>
                            <td>Whether to automatically manage layering.</td>
                        </tr>
                        <tr>
                            <td>baseZIndex</td>
                            <td>number</td>
                            <td>0</td>
                            <td>Base zIndex value to use in layering.</td>
                        </tr>
                        <tr>
                            <td>defaultLabel</td>
                            <td>string</td>
                            <td>Choose</td>
                            <td>Label to display when there are no selections. Deprecated: Use placeholder instead.</td>
                        </tr>
                        <tr>
                            <td>dataKey</td>
                            <td>string</td>
                            <td>null</td>
                            <td>A property to uniquely identify a value in options.</td>
                        </tr>
                        <tr>
                            <td>disabled</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>When present, it specifies that the element should be disabled.</td>
                        </tr>
                        <tr>
                            <td>displaySelectedLabel</td>
                            <td>boolean</td>
                            <td>true</td>
                            <td>Whether to show labels of selected item labels or use default label.</td>
                        </tr>
                        <tr>
                            <td>dropdownIcon</td>
                            <td>string</td>
                            <td>pi pi-chevron-down</td>
                            <td>Icon class of the dropdown icon.</td>
                        </tr>
                        <tr>
                            <td>emptyFilterMessage</td>
                            <td>string</td>
                            <td>No results found</td>
                            <td>Text to display when filtering does not return any results.</td>
                        </tr>
                        <tr>
                            <td>filter</td>
                            <td>boolean</td>
                            <td>true</td>
                            <td>When specified, displays an input field to filter the items on keyup.</td>
                        </tr>
                        <tr>
                            <td>filterMatchMode</td>
                            <td>string</td>
                            <td>contains</td>
                            <td>Defines how the items are filtered, valid values are "contains" (default) "startsWith", "endsWith", "equals", "notEquals", "in", "lt", "lte", "gt" and "gte".</td>
                        </tr>
                        <tr>
                            <td>filterValue</td>
                            <td>string</td>
                            <td>null</td>
                            <td>When specified, filter displays with this value.</td>
                        </tr>
                        <tr>
                            <td>filterLocale</td>
                            <td>string</td>
                            <td>undefined</td>
                            <td>Locale to use in filtering. The default locale is the host environment's current locale.</td>
                        </tr>
                        <tr>
                            <td>filterBy</td>
                            <td>string</td>
                            <td>null</td>
                            <td>When filtering is enabled, filterBy decides which field or fields (comma separated) to search against.</td>
                        </tr>
                        <tr>
                            <td>filterPlaceHolder</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Defines placeholder of the filter input.</td>
                        </tr>
                        <tr>
                            <td>hideTransitionOptions</td>
                            <td>string</td>
                            <td>.1s linear</td>
                            <td>Transition options of the hide animation.</td>
                        </tr>
                        <tr>
                            <td>inputId</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Identifier of the focus input to match a label defined for the component.</td>
                        </tr>
                        <tr>
                            <td>maxSelectedLabels</td>
                            <td>number</td>
                            <td>3</td>
                            <td>Decides how many selected item labels to show at most.</td>
                        </tr>
                        <tr>
                            <td>name</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Name of the input element.</td>
                        </tr>
                        <tr>
                            <td>options</td>
                            <td>array</td>
                            <td>null</td>
                            <td>An array of objects to display as the available options.</td>
                        </tr>
                        <tr>
                            <td>optionLabel</td>
                            <td>string</td>
                            <td>label</td>
                            <td>Name of the label field of an option.</td>
                        </tr>
                        <tr>
                            <td>optionValue</td>
                            <td>string</td>
                            <td>value</td>
                            <td>Name of the value field of an option.</td>
                        </tr>
                        <tr>
                            <td>optionDisabled</td>
                            <td>string</td>
                            <td>disabled</td>
                            <td>Name of the disabled field of an option.</td>
                        </tr>
                        <tr>
                            <td>optionGroupLabel</td>
                            <td>string</td>
                            <td>label</td>
                            <td>Name of the label field of an option group.</td>
                        </tr>
                        <tr>
                            <td>optionGroupChildren</td>
                            <td>string</td>
                            <td>items</td>
                            <td>Name of the options field of an option group.</td>
                        </tr>
                        <tr>
                            <td>group</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Whether to display options as grouped when nested options are provided.</td>
                        </tr>
                        <tr>
                            <td>overlayVisible</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Specifies the visibility of the options panel.</td>
                        </tr>
                        <tr>
                            <td>panelStyle</td>
                            <td>object</td>
                            <td>null</td>
                            <td>Inline style of the overlay panel.</td>
                        </tr>
                        <tr>
                            <td>placeholder</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Label to display when there are no selections.</td>
                        </tr>
                        <tr>
                            <td>readonly</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>When present, it specifies that the component cannot be edited.</td>
                        </tr>
                        <tr>
                            <td>emptyMessage</td>
                            <td>string</td>
                            <td>No records found.</td>
                            <td>Text to display when there is no data. Defaults to global value in i18n translation configuration.</td>
                        </tr>
                        <tr>
                            <td>emptyFilterMessage</td>
                            <td>string</td>
                            <td>No results found</td>
                            <td>Text to display when filtering does not return any results. Defaults to global value in i18n translation configuration.</td>
                        </tr>
                        <tr>
                            <td>resetFilterOnHide</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Clears the filter value when hiding the dropdown.</td>
                        </tr>
                        <tr>
                            <td>scrollHeight</td>
                            <td>string</td>
                            <td>200px</td>
                            <td>Height of the viewport in pixels, a scrollbar is defined if height of list exceeds this value.</td>
                        </tr>
                        <tr>
                            <td>selectedItemsLabel</td>
                            <td>string</td>
                            <td>ellipsis</td>
                            <td>Label to display after exceeding max selected labels e.g. (&#123;0&#125; items selected), defaults "ellipsis" keyword to indicate a text-overflow.</td>
                        </tr>
                        <tr>
                            <td>selectionLimit</td>
                            <td>number</td>
                            <td>null</td>
                            <td>Number of maximum options that can be selected.</td>
                        </tr>
                        <tr>
                            <td>showHeader</td>
                            <td>boolean</td>
                            <td>true</td>
                            <td>Whether to show the header.</td>
                        </tr>
                        <tr>
                            <td>showTransitionOptions</td>
                            <td>string</td>
                            <td>.12s cubic-bezier(0, 0, 0.2, 1)</td>
                            <td>Transition options of the show animation.</td>
                        </tr>
                        <tr>
                            <td>showToggleAll</td>
                            <td>boolean</td>
                            <td>true</td>
                            <td>Whether to show the checkbox at header to toggle all items at once.</td>
                        </tr>
                        <tr>
                            <td>style</td>
                            <td>object</td>
                            <td>null</td>
                            <td>Inline style of the element.</td>
                        </tr>
                        <tr>
                            <td>styleClass</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Style class of the element.</td>
                        </tr>
                        <tr>
                            <td>tabindex</td>
                            <td>number</td>
                            <td>null</td>
                            <td>Index of the element in tabbing order.</td>
                        </tr>
                        <tr>
                            <td>tooltip</td>
                            <td>any</td>
                            <td>null</td>
                            <td>Advisory information to display in a tooltip on hover.</td>
                        </tr>
                        <tr>
                            <td>tooltipStyleClass</td>
                            <td>string</td>
                            <td>null</td>
                            <td>Style class of the tooltip.</td>
                        </tr>
                        <tr>
                            <td>tooltipPosition</td>
                            <td>string</td>
                            <td>top</td>
                            <td>Position of the tooltip, valid values are right, left, top and bottom.</td>
                        </tr>
                        <tr>
                            <td>tooltipPositionStyle</td>
                            <td>string</td>
                            <td>absolute</td>
                            <td>Type of CSS position.</td>
                        </tr>
                        <tr>
                            <td>showClear</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>When enabled, a clear icon is displayed to clear the value.</td>
                        </tr>
                        <tr>
                            <td>virtualScroll</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Whether the data should be loaded on demand during scroll.</td>
                        </tr>
                        <tr>
                            <td>virtualScrollItemSize</td>
                            <td>number</td>
                            <td>null</td>
                            <td>Height of an item in the list for VirtualScrolling.</td>
                        </tr>
                        <tr>
                            <td>virtualScrollOptions</td>
                            <td>ScrollerOptions</td>
                            <td>false</td>
                            <td>Whether to use the scroller feature. The properties of <a href="#" [routerLink]="['/theming']">scroller</a> component can be used like an object in it.</td>
                        </tr>
                        <tr>
                            <td>lazy</td>
                            <td>boolean</td>
                            <td>false</td>
                            <td>Defines if data is loaded and interacted with in lazy manner.</td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <h5>Events</h5>
            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                    <tr>
                        <th>Name</th>
                        <th>Parameters</th>
                        <th>Description</th>
                    </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>onClick</td>
                            <td>event: Click event</td>
                            <td>Callback to invoke when component is clicked.</td>
                        </tr>
                        <tr>
                            <td>onChange</td>
                            <td>event.originalEvent: browser event<br />
                                event.value: Current selected values<br />
                                event.itemValue: Toggled item value
                            </td>
                            <td>Callback to invoke when value changes.</td>
                        </tr>
                        <tr>
                            <td>onFilter</td>
                            <td>event.originalEvent: Browser event <br />
                                event.filter: Filter value used in filtering.</td>
                            <td>Callback to invoke when data is filtered.</td>
                        </tr>
                        <tr>
                            <td>onFocus</td>
                            <td>event.originalEvent: browser event</td>
                            <td>Callback to invoke when multiselect receives focus.</td>
                        </tr>
                        <tr>
                            <td>onBlur</td>
                            <td>event.originalEvent: browser event</td>
                            <td>Callback to invoke when multiselect loses focus.</td>
                        </tr>
                        <tr>
                            <td>onPanelShow</td>
                            <td>-</td>
                            <td>Callback to invoke when overlay panel becomes visible.</td>
                        </tr>
                        <tr>
                            <td>onPanelHide</td>
                            <td>-</td>
                            <td>Callback to invoke when overlay panel becomes hidden.</td>
                        </tr>
                        <tr>
                            <td>onClear</td>
                            <td>-</td>
                            <td>Callback to invoke when input field is cleared.</td>
                        </tr>
                        <tr>
                            <td>onLazyLoad</td>
                            <td>event.first: First index of the new data range to be loaded.<br/>
                                event.last: Last index of the new data range to be loaded.
                            </td>
                            <td>Callback to invoke in lazy mode to load new data.</td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <h5>Templates</h5>
            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Parameters</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>item</td>
                            <td>$implicit: Data of the item</td>
                        </tr>
                        <tr>
                            <td>group</td>
                            <td>$implicit: Data of the group item</td>
                        </tr>
                         <tr>
                            <td>selectedItems</td>
                            <td>$implicit: value</td>
                        </tr>
                        <tr>
                            <td>header</td>
                            <td>-</td>
                        </tr>
                        <tr>
                            <td>filter</td>
                            <td>options.filter: Callback to filter data by the value param<br />
                                options.reset: Resets the filter.
                            </td>
                        </tr>
                        <tr>
                            <td>empty</td>
                            <td>-</td>
                        </tr>
                        <tr>
                            <td>emptyfilter</td>
                            <td>-</td>
                        </tr>
                        <tr>
                            <td>footer</td>
                            <td>-</td>
                        </tr>
                        <tr>
                            <td>loader</td>
                            <td>options: Options of the scroller on loading. *This template can be used with virtualScroll.</td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <h5>Styling</h5>
            <p>Following is the list of structural style classes, for theming classes visit <a href="#" [routerLink]="['/theming']">theming page</a>.</p>
            <div class="doc-tablewrapper">
                <table class="doc-table">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Element</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>p-multiselect</td>
                            <td>Container element.</td>
                        </tr>
                        <tr>
                            <td>p-multiselect-label-container</td>
                            <td>Container of the label to display selected items.</td>
                        </tr>
                        <tr>
                            <td>p-multiselect-label</td>
                            <td>Label to display selected items.</td>
                        </tr>
                        <tr>
                            <td>p-multiselect-trigger</td>
                            <td>Dropdown button.</td>
                        </tr>
                        <tr>
                            <td>p-multiselect-filter-container</td>
                            <td>Container of filter input.</td>
                        </tr>
                        <tr>
                            <td>p-multiselect-panel</td>
                            <td>Overlay panel for items.</td>
                        </tr>
                        <tr>
                            <td>p-multiselect-items</td>
                            <td>List container of items.</td>
                        </tr>
                        <tr>
                            <td>p-multiselect-item</td>
                            <td>An item in the list.</td>
                        </tr>
                        <tr>
                            <td>p-multiselect-open</td>
                            <td>Container element when overlay is visible.</td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <h5>Dependencies</h5>
            <p>None.</p>
        </p-tabPanel>

        <p-tabPanel header="Source">
            <a href="https://github.com/primefaces/primeng/tree/master/src/app/showcase/components/multiselect" class="btn-viewsource" target="_blank">
                <span>View on GitHub</span>
            </a>
            <a href="https://stackblitz.com/edit/primeng-multiselect-demo" class="btn-viewsource" style="margin-left: .5em;" target="_blank">
                <span>Edit in StackBlitz</span>
            </a>
<app-code lang="markup" ngNonBindable ngPreserveWhitespaces>
&lt;div class="card"&gt;
    &lt;h5&gt;Template Mode&lt;/h5&gt;
    &lt;p-multiSelect [options]="cities" [(ngModel)]="selectedCities1" defaultLabel="Select a City" optionLabel="name" selectedItemsLabel="&#123;0&#125; items selected"&gt;&lt;/p-multiSelect&gt;

    &lt;h5&gt;Elipsis Mode&lt;/h5&gt;
    &lt;p-multiSelect [options]="cities" [(ngModel)]="selectedCities2" defaultLabel="Select a City" optionLabel="name"&gt;&lt;/p-multiSelect&gt;

    &lt;h5&gt;Chips&lt;/h5&gt;
    &lt;p-multiSelect [options]="cities" [(ngModel)]="selectedCities3" defaultLabel="Select a City" optionLabel="name" display="chip"&gt;&lt;/p-multiSelect&gt;

    &lt;h5&gt;Grouped&lt;/h5&gt;
    &lt;p-multiSelect [options]="groupedCities" [group]="true" [(ngModel)]="selectedCities4" defaultLabel="Select a City" scrollHeight="250px" display="chip"&gt;
        &lt;ng-template let-group pTemplate="group"&gt;
            &lt;div class="flex align-items-center"&gt;
                &lt;img src="assets/showcase/images/demo/flag/flag_placeholder.png" [class]="'mr-2 flag flag-' + group.value" style="width: 20px"/&gt;
                &lt;span&gt;&#123;&#123;group.label&#125;&#125;&lt;/span&gt;
            &lt;/div&gt;
        &lt;/ng-template&gt;
    &lt;/p-multiSelect&gt;

    &lt;h5&gt;Advanced with Templating and Filtering&lt;/h5&gt;
    &lt;p-multiSelect [options]="countries" [(ngModel)]="selectedCountries1" defaultLabel="Select a Country" optionLabel="name" class="multiselect-custom"&gt;
        &lt;ng-template let-value pTemplate="selectedItems"&gt;
            &lt;div class="country-item country-item-value" *ngFor="let option of selectedCountries1"&gt;
                &lt;img src="assets/showcase/images/demo/flag/flag_placeholder.png" [class]="'flag flag-' + option.code.toLowerCase()" /&gt;
                &lt;div&gt;&#123;&#123;option.name&#125;&#125;&lt;/div&gt;
            &lt;/div&gt;
            &lt;div *ngIf="!selectedCountries1 || selectedCountries1.length === 0" class="country-placeholder"&gt;
                Select Countries
            &lt;/div&gt;
        &lt;/ng-template&gt;
        &lt;ng-template let-country pTemplate="item"&gt;
            &lt;div class="country-item"&gt;
                &lt;img src="assets/showcase/images/demo/flag/flag_placeholder.png" [class]="'flag flag-' + country.code.toLowerCase()" /&gt;
                &lt;div&gt;&#123;&#123;country.name&#125;&#125;&lt;/div&gt;
            &lt;/div&gt;
        &lt;/ng-template&gt;
    &lt;/p-multiSelect&gt;

    &lt;h5&gt;Virtual Scroll&lt;/h5&gt;
    &lt;p-multiSelect [options]="virtualCountries" [showToggleAll]="false" [(ngModel)]="selectedCountries2" optionLabel="name" [virtualScroll]="true" [filter]="true" [virtualScrollItemSize]="43" class="multiselect-custom-virtual-scroll"&gt;
        &lt;ng-template let-country pTemplate="item"&gt;
            &lt;div class="country-item"&gt;
                &lt;img src="assets/showcase/images/demo/flag/flag_placeholder.png" [class]="'flag flag-' + country.code.toLowerCase()" /&gt;
                &lt;div&gt;&#123;&#123;country.name&#125;&#125;&lt;/div&gt;
            &lt;/div&gt;
        &lt;/ng-template&gt;
    &lt;/p-multiSelect&gt;
&lt;/div&gt;
</app-code>

<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
import &#123;Component&#125; from '@angular/core';
import &#123;CountryService&#125; from '../../service/countryservice';

interface City &#123;
    name: string,
    code: string
&#125;

interface Country &#123;
    name: string,
    code: string
&#125;

@Component(&#123;
    templateUrl: './multiselectdemo.html',
    styleUrls: ['./multiselectdemo.scss']
&#125;)
export class MultiSelectDemo &#123;

    selectedCities1: City[];

    selectedCities2: City[];

    selectedCities3: any[];

    selectedCities4: any[];

    selectedCountries1: Country[];

    selectedCountries2: Country[];

    cities: City[];

    groupedCities: SelectItemGroup[];

    countries: City[];

    virtualCountries: Country[];

    constructor(private countryService: CountryService) &#123;
        this.cities = [
            &#123;name: 'New York', code: 'NY'&#125;,
            &#123;name: 'Rome', code: 'RM'&#125;,
            &#123;name: 'London', code: 'LDN'&#125;,
            &#123;name: 'Istanbul', code: 'IST'&#125;,
            &#123;name: 'Paris', code: 'PRS'&#125;
        ];

        this.countries = [
            &#123;name: 'Australia', code: 'AU'&#125;,
            &#123;name: 'Brazil', code: 'BR'&#125;,
            &#123;name: 'China', code: 'CN'&#125;,
            &#123;name: 'Egypt', code: 'EG'&#125;,
            &#123;name: 'France', code: 'FR'&#125;,
            &#123;name: 'Germany', code: 'DE'&#125;,
            &#123;name: 'India', code: 'IN'&#125;,
            &#123;name: 'Japan', code: 'JP'&#125;,
            &#123;name: 'Spain', code: 'ES'&#125;,
            &#123;name: 'United States', code: 'US'&#125;
        ];

        this.groupedCities = [
            &#123;
                label: 'Germany', value: 'de',
                items: [
                    &#123;label: 'Berlin', value: 'Berlin'&#125;,
                    &#123;label: 'Frankfurt', value: 'Frankfurt'&#125;,
                    &#123;label: 'Hamburg', value: 'Hamburg'&#125;,
                    &#123;label: 'Munich', value: 'Munich'&#125;
                ]
            &#125;,
            &#123;
                label: 'USA', value: 'us',
                items: [
                    &#123;name: 'Chicago', value: 'Chicago'&#125;,
                    &#123;name: 'Los Angeles', value: 'Los Angeles'&#125;,
                    &#123;name: 'New York', value: 'New York'&#125;,
                    &#123;name: 'San Francisco', value: 'San Francisco'&#125;
                ]
            &#125;,
            &#123;
                label: 'Japan', value: 'jp',
                items: [
                    &#123;name: 'Kyoto', value: 'Kyoto'&#125;,
                    &#123;name: 'Osaka', value: 'Osaka'&#125;,
                    &#123;name: 'Tokyo', value: 'Tokyo'&#125;,
                    &#123;name: 'Yokohama', value: 'Yokohama'&#125;
                ]
            &#125;
        ];

        this.countryService.getCountries().then(countries =&gt; &#123;
            this.virtualCountries = countries;
        &#125;);
    &#125;

&#125;
</app-code>

<app-code lang="css" ngNonBindable ngPreserveWhitespaces>
 :host ::ng-deep .p-multiselect &#123;
    min-width: 15rem;
    width: 18rem;
&#125;

:host ::ng-deep .multiselect-custom &#123;
    .p-multiselect-label &#123;
        padding-top: .5rem;
        padding-bottom: .5rem;
    &#125;

    .country-item-value &#123;
        padding: .25rem .5rem;
        border-radius: 3px;
        display: inline-flex;
        margin-right: .5rem;
        background-color: var(--primary-color);
        color: var(--primary-color-text);

        img.flag &#123;
            width: 17px;
        &#125;
    &#125;

    .country-placeholder &#123;
        padding: 0.25rem;
    &#125;
&#125;
:host ::ng-deep &#123;
    @media screen and (max-width: 640px) &#123;
        .p-multiselect &#123;
            width: 100%;
        &#125;
    &#125;
&#125;
</app-code>
<app-code lang="typescript" ngNonBindable ngPreserveWhitespaces>
@Injectable()
export class CountryService &#123;

    constructor(private http: Http) &#123;&#125;

    getCountries() &#123;
        return this.http.get('showcase/resources/data/countries.json')
                    .toPromise()
                    .then(res => &lt;any[]&gt; res.json().data)
                    .then(data => &#123; return data; &#125;);
    &#125;
&#125;
</app-code>
        </p-tabPanel>
        <p-tabPanel header="StackBlitz">
            <ng-template pTemplate="content">
                <iframe src="https://stackblitz.com/edit/primeng-multiselect-demo?embed=1" style="width: 100%; height: 768px; border: none;"></iframe>
            </ng-template>
        </p-tabPanel>
    </p-tabView>
</div>
